package com.api.client;

import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.scribe.builder.api.Api;
import org.scribe.builder.api.DefaultApi10a;
import org.scribe.model.OAuthConfig;
import org.scribe.model.OAuthRequest;
import org.scribe.model.Response;
import org.scribe.model.SignatureType;
import org.scribe.model.Token;
import org.scribe.model.Verb;
import org.scribe.model.Verifier;
import org.scribe.oauth.OAuthService;

public class OAuthProvider {

	private Log logger = LogFactory.getLog(getClass());

	private final OAuthService service;

	private final String authorizationEndpoint;

	private final Token consumerToken;

	public OAuthProvider(String requestEndpoint, String accessEndpoint, String authorizationEndpoint, Token consumerToken) {

		if (requestEndpoint == null || accessEndpoint == null || authorizationEndpoint == null || consumerToken == null) {

			throw new IllegalArgumentException("Constructor parameters cannot be null");
		}

		if (consumerToken.getToken() == null || consumerToken.getSecret() == null) {

			throw new IllegalArgumentException("Consumer tokens cannot be null");
		}

		Api api = getDefaultApi(requestEndpoint, accessEndpoint);
		this.service = api.createService(new OAuthConfig(consumerToken.getToken(), consumerToken.getSecret(), "oob", SignatureType.Header, null, null));
		this.authorizationEndpoint = authorizationEndpoint;
		this.consumerToken = consumerToken;
	}

	public Token getAccessToken(String username, String password) {

		if (username == null || password == null) {

			throw new IllegalStateException("Username and password cannot be null");
		}

		Token requestToken = null;

		try {
			requestToken = service.getRequestToken();
		} catch (Exception e) {

			throw new IllegalStateException(String.format("Couldn't get request token for consumerKeys: ['%s', '%s']", consumerToken.getToken(), consumerToken.getSecret()), e);
		}

		OAuthRequest authorizeRequest = new OAuthRequest(Verb.POST, authorizationEndpoint);

		authorizeRequest.addBodyParameter("username", username);
		authorizeRequest.addBodyParameter("password", password);
		authorizeRequest.addBodyParameter("request_token", requestToken.getToken());

		Response authorizeResponse = authorizeRequest.send();

		if (!authorizeResponse.isSuccessful()) {

			throw new IllegalStateException(String.format("Couldn't authorize api user - Username: '%s', Password: '%s', RequestToken: '%s', consumerKeys: ['%s', '%s'] - Code: '%s' Message: '%s'",
					username, password, requestToken.getToken(), consumerToken.getToken(), consumerToken.getSecret(), authorizeResponse.getCode(), authorizeResponse.getBody()));
		}

		try {

			Token accessToken = service.getAccessToken(requestToken, new Verifier(""));

			logger.info(String.format("User logged in: '%s'/'%s'", username, password));

			return accessToken;
		} catch (Exception e) {

			throw new IllegalStateException(String.format("Couldn't get accessToken - Username: '%s', Password: '%s', RequestToken: ['%s', '%s'], consumerKeys: ['%s', '%s']", username, password,
					requestToken.getToken(), requestToken.getSecret(), consumerToken.getToken(), consumerToken.getSecret()), e);
		}
	}

	private Api getDefaultApi(final String requestEndpoint, final String accessEndpoint) {

		return new DefaultApi10a() {
			@Override
			public String getRequestTokenEndpoint() {
				return requestEndpoint;
			}

			@Override
			public String getAccessTokenEndpoint() {
				return accessEndpoint;
			}

			@Override
			public String getAuthorizationUrl(Token requestToken) {
				return null;
			}
		};
	}
}
